package br.com.gbvbahia.commons.dao;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import br.com.gbvbahia.commons.modelos.EntityInterface;
import br.com.gbvbahia.commons.utils.AndroidUtils;

public abstract class InterfaceDAO<T extends EntityInterface, ID extends Serializable> {
	protected static SQLiteOpenHelper db;

	protected abstract String getTableName();

	protected abstract String[] getColumNames();

	protected abstract String getColumnOrderDefault();
	
	protected abstract String getColumnIdName();

	protected abstract T getFromCursor(Cursor cursor);

	protected abstract void populateContentValues(ContentValues cv, T t);

	protected InterfaceDAO(SQLiteOpenHelper db) {
		super();
		if (InterfaceDAO.db == null)
			InterfaceDAO.db = db;
	}

	public synchronized SQLiteDatabase getDataBase() {
		return InterfaceDAO.db.getWritableDatabase();
	}

	/**
	 * Insere objeto no banco sem chamar prepareInsert de EntityInterface.
	 * 
	 * @param vo
	 * @return
	 */
	public long insert(T vo) {
		ContentValues cv = new ContentValues();
		if (vo.gerarId()) {
			vo.setId(AndroidUtils.gerarIdentificador());
		}
		populateContentValues(cv, vo);
		return getDataBase().insert(getTableName(), null, cv);
	}

	/**
	 * Insere objeto no banco chamando prepareInsert de EntityInterface.
	 * 
	 * @param vo
	 * @return
	 */
	public long insertPrepare(T vo) {
		vo.prepareInsert();
		return insert(vo);
	}

	public long delete(T vo) {
		return getDataBase().delete(getTableName(), getColumnIdName() + "=?",
				new String[] { vo.getId().toString() });
	}

	/**
	 * Atualiza o objeto no banco de dados sem chamar prepareUpdate de
	 * EntityInterface.
	 * 
	 * @param vo
	 * @return
	 */
	public long update(T vo) {
		ContentValues cv = new ContentValues();
		populateContentValues(cv, vo);
		return getDataBase().update(getTableName(), cv, getColumnIdName() + "=?",
				new String[] { vo.getId().toString() });
	}

	/**
	 * Atualiza o objeto no banco de dados chamando prepareUpdate de
	 * EntityInterface.
	 * 
	 * @param vo
	 * @return
	 */
	public long updatePrepare(T vo) {
		vo.prepareUpdate();
		return update(vo);
	}

	public T getByID(ID id) {
		Cursor cursor = null;
		try {
			cursor = getDataBase().query(getTableName(), getColumNames(),
					getColumnIdName() + "=?", new String[] { id.toString() }, null, null, null);
			T toReturn = null;
			if (cursor.moveToFirst()) {
				toReturn = getFromCursor(cursor);

			}
			return toReturn;
		} finally {
			if (cursor != null && !cursor.isClosed()) {
				cursor.close();
			}
		}
	}

	public List<T> getAll() {
		Cursor cursor = null;
		try {
			cursor = getDataBase().rawQuery(
					"Select * From " + getTableName() + " Order by "
							+ getColumnOrderDefault(), null);
			List<T> toReturn = new ArrayList<T>();
			while (cursor.moveToNext()) {
				T toInsert = getFromCursor(cursor);
				toReturn.add(toInsert);
			}
			return toReturn;
		} finally {
			if (cursor != null && !cursor.isClosed()) {
				cursor.close();
			}
		}
	}

	public T getFirst() {
		Cursor cursor = null;
		try {
			cursor = getDataBase().query(getTableName(), getColumNames(), null,
					null, null, null, getColumnOrderDefault(), "1");
			T toReturn = null;
			if (cursor.moveToFirst()) {
				toReturn = getFromCursor(cursor);

			}
			return toReturn;
		} finally {
			if (cursor != null && !cursor.isClosed()) {
				cursor.close();
			}
		}
	}
}
